// ! Two memory operation access continuously the same set, second access will 
//   read fault flags and replacement info from memory, we need a buffer to store
//   flags and info updated by previous access. This buffer should be added!!!


module evict_mng 
#(
parameter NUM_WAY   = 4,            // NUM_WAY = 2**WAY_WIDTH,
parameter SET_WIDTH = 10,           // SET_WIDTH=ADDR_MEM_WIDTH - ADDR_CACHE_WIDTH - WAY_WIDTH,
parameter TAG_WIDTH = 11           //ADDR_MEM_WIDTH - CACHE_LINE_WIDTH - SET_WIDTH
)

(
    input   clk,
    input   rst,
    input   valid_arb2tag,
    output  ready_arb2tag,

    input   [3:0]   evict_policy,
    input   [31:0]  data_i,
    output  [31:0]  data_o,   
    output          en_wr,

    input                   cache_hit,   // hit flag of each way
    output  reg [NUM_WAY-1:0]   way_evict,
    output  [NUM_WAY-1:0]   way_hit,
    input   [NUM_WAY-1:0]   empty,
    input   [NUM_WAY-1:0]   valid
    );


//----------------------------------------------------
//Wire and reg declarations
//----------------------------------------------------
wire  [0:NUM_WAY-1]   empty_way ;
wire  [0:NUM_WAY-1]   valid_way ;
wire  [0:NUM_WAY-1]   dirty_way ;
wire  [0:NUM_WAY-1]   lock_way  ;
wire  [TAG_WIDTH-1:0] tag_cache  [0:NUM_WAY-1] ;
wire  [TAG_WIDTH+3:0] data_rd_mem [0:NUM_WAY-1] ;

wire  [TAG_WIDTH-1:0] tag_rqst_gated;


wire en_plru;
wire sel_plru;

wire [NUM_WAY-2:0]  node_plru;

reg  [NUM_WAY-2:0]  q_node_plru;
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// Cache replacement policies
//
// 32 bits replacement information definition
// |31 -- 16|15 -- 0|
// |  PLRU  | XXXXX |
//------------------------------------------------------------------- 
//-------------------------------------------------------------------

//-------------------------------------------------------------------
// Split 32 bits of replacement info with gating signal
//-------------------------------------------------------------------

//-------------------------------------------------------------------
// PLRU (tree) manager (Maximum support 16 Ways)
// It reads node bits from replace_ifo_mem and writes back updated node
// bits in the next clock cycle.
// On a cache update, on a cache hit, the node bits on the path leading
// to the accessed way will be flipped. on a cache miss, if it exists
// the empty ways, fill one empty way by ascending order of way number 
// and don't update node bits. if all ways aren't empty, select an 
// ecvited way by PLRU algorithme, update node bits.
//------------------------------------------------------------------- 

// Split 32 bits of replacement info with gating signal en_plru
assign en_plru      = sel_plru & ready_arb2tag & valid_arb2tag;   //!! CONSIDER READY AND VALID for low power
assign node_plru    = (en_plru) ? data_i[31:31-NUM_WAY] : {(NUM_WAY-2){1'b0}};  
assign way_hit_plru = (en_plru) ? way_hit : {NUM_WAY{1'b0}};

generate if (NUM_WAY == 2) begin    // 2-ways associative set cache
end else if (NUM_WAY == 4) begin    // 4-ways associative set cache
always @(*)
begin
    if (!rst) begin
        //s;
    end else begin
        
        // On cache hit, flip q_node_plru to update node bits info of
        // PLRU Tree. On a cache miss 
        if (cache_hit) begin 
            case (way_hit_plru)
                4'b0001 : begin
                    q_node_plru[2] = ~q_node_plru[2]; 
                    q_node_plru[1] = ~q_node_plru[1];
                    q_node_plru[0] = q_node_plru[0];
                end

                4'b0010 : begin
                    q_node_plru[2] = ~q_node_plru[2]; 
                    q_node_plru[1] = ~q_node_plru[1];
                    q_node_plru[0] = q_node_plru[0];
                end

                4'b0100 : begin
                    q_node_plru[2] = ~q_node_plru[2]; 
                    q_node_plru[1] = q_node_plru[1];
                    q_node_plru[0] = ~q_node_plru[0];
                end

                4'b1000 : begin
                    q_node_plru[2] = ~q_node_plru[2]; 
                    q_node_plru[1] = q_node_plru[1];
                    q_node_plru[0] = ~q_node_plru[0];
                end

                default : begin
                    q_node_plru[2] = q_node_plru[2]; 
                    q_node_plru[1] = q_node_plru[1];
                    q_node_plru[0] = q_node_plru[0];
                end
            endcase

        end else begin  
            case (empty)

                // All ways aren't empty in a set
                4'b0000 : begin
                    case (node_plru[2:0])
                        3'b00? : begin
                            q_node_plru[2] = 1'b1; 
                            q_node_plru[1] = 1'b1;
                            q_node_plru[0] = q_node_plru[0];
                            way_evict    = 4'b0001;
                        end

                        3'b01? : begin
                            q_node_plru[2] = 1'b1; 
                            q_node_plru[1] = 1'b0;
                            q_node_plru[0] = q_node_plru[0];
                            way_evict    = 4'b0010;
                        end

                        3'b1?0 : begin
                            q_node_plru[2] = 1'b0; 
                            q_node_plru[1] = q_node_plru[1];
                            q_node_plru[0] = 1'b1;
                            way_evict    = 4'b0100;
                        end

                        3'b1?1 : begin
                            q_node_plru[2] = 1'b0; 
                            q_node_plru[1] = q_node_plru[1];
                            q_node_plru[0] = 1'b0;
                            way_evict    = 4'b1000;
                        end
                    endcase
                end
                
                // Way 0 is empty
                4'b???1 : begin
                    way_evict = 4'b0001;
                end

                // Way 1 is empty
                4'bxx1x : begin
                    way_evict = 4'b0010;
                end

                // Way 2 is empty
                4'bx1xx : begin
                    way_evict = 4'b0100;
                end

                // Way 3 is empty
                4'b1xxx : begin
                    way_evict = 4'b1000;
                end

                default : begin
                end
            endcase
        end
    end
end  
end else if (NUM_WAY == 8) begin    // 8-ways associative set cache
end
endgenerate

endmodule 